package mybatis.interceptor.example.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.RawSqlSource;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.util.StopWatch;

import java.util.Properties;

/**
 * @author guan.xin
 * @title TpTenantReadInterceptor
 * @description
 * @create 2022-04-21 13:17
 * @since JDK8
 */
@Slf4j
@Intercepts(value = {
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class TpTenantReadInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        BoundSql sqlObject = mappedStatement.getBoundSql(invocation.getArgs()[1]);
        String newSql = sqlObject.getSql() + " LIMIT 1";

        //构建新的sql对象
        Class<?> type = mappedStatement.getParameterMap().getType();
        SqlSource sqlSource = new RawSqlSource(mappedStatement.getConfiguration(), newSql, type);
        MetaObject metaObject = SystemMetaObject.forObject(mappedStatement);
        metaObject.setValue("sqlSource", sqlSource);

        try {
            return invocation.proceed();
        } finally {
            stopWatch.stop();
            log.info("sql: {}", "TpTenantReadInterceptor");
            log.info("sql: {}", newSql);
            log.info("cost: {}", stopWatch.getLastTaskInfo().getTimeMillis());
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
